using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace pong1
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class CollisionDetector : Microsoft.Xna.Framework.GameComponent
    {

        EventCollection eventCollection;    // Stores reference to pending events list
        String[] eventsForThisGameObjectArray;  // Stores a list of events that this object polls for
        List<ObjectAndRectangle> rectangles;
        String strEventReceiver;        // Event receiver name of the Collision Detector

        struct ObjectAndRectangle 
        {
            public String objectName;
            public Rectangle rectangle;
        }
        public CollisionDetector(Game game)
            : base(game)
        {
            eventCollection = (EventCollection)Game.Services.GetService(typeof(EventCollection));
            rectangles = new List<ObjectAndRectangle>();
            strEventReceiver = "collisiondetector";

        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            eventCollection.RegisterForEvent("ballposition", strEventReceiver);    // register for 'ballposition' event if you are CollisionDetector
            eventCollection.RegisterForEvent("paddle1position", strEventReceiver);    // register for 'paddle1position' event if you are CollisionDetector
            eventCollection.RegisterForEvent("paddle2position", strEventReceiver);    // register for 'paddle2position' event if you are CollisionDetector
            String eventsForThisBall;
            eventsForThisBall = eventCollection.GetEventsForReceiver(strEventReceiver);
            eventsForThisGameObjectArray = eventsForThisBall.Split(',');
            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // Process events for collision detector. Collision detector will create the rectangles for each game object.
            if (!eventCollection.IsEmpty())
            {
                Event e;
                for (int j = 0; j < eventsForThisGameObjectArray.Length; j++)       // For each event this paddle is listening for, retrieve and process the event
                {
                    e = eventCollection.RetrieveEvent(eventsForThisGameObjectArray[j]);

                    if (e != null)
                    {
                        processEvent(e);
                    }
                }

            }

            // Detect if any collsions have occurred
            detectCollisions();
            base.Update(gameTime);
        }


        /// <summary>
        /// The event processor for all events handled by CollisionDetector
        /// 
        /// </summary>
        private void processEvent(Event e)
        {

            switch (e.EventName)
            {
                case "paddle1position":        // Create a rectangle for each paddle and ball using it's position
                case "paddle2position":
                case "ballposition":
                    ObjectAndRectangle rect = new ObjectAndRectangle();
                    rect.rectangle = new Rectangle(Convert.ToInt32(e.EventArguments[0].ArgumentValue), Convert.ToInt32(e.EventArguments[1].ArgumentValue), Convert.ToInt32(e.EventArguments[2].ArgumentValue), Convert.ToInt32(e.EventArguments[3].ArgumentValue));
                    rect.objectName = e.EventName.Replace("position", "");
                    rectangles.Add(rect);
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        ///  After getting all the objects' rectangles, figure out if any collisions have occurred, and place messages on the event collection
        /// </summary>
        private void detectCollisions() 
        {
            
            foreach (ObjectAndRectangle r1 in rectangles)
            {
                foreach (ObjectAndRectangle r2 in rectangles)
                {
                    if (!r1.Equals(r2))
                    {
                        if (r1.rectangle.Intersects(r2.rectangle))
                        {
                            // Send message to r1 and r2 that collision has occurred
                            Event test = eventCollection.RetrieveEvent("collisiondetector" + r1.objectName);   // Remove the old such event if it's still on the EventCollection
                            Event e = new Event();
                            e.EventName = "collisiondetector" + r1.objectName;

                            e.EventArguments[0].ArgumentName = "objectwithwhichcollisiontookplace";
                            e.EventArguments[0].ArgumentType = "string";
                            e.EventArguments[0].ArgumentValue = r2.objectName;

                            Rectangle rIntersect = Rectangle.Intersect(r1.rectangle, r2.rectangle);
                            if (!rIntersect.IsEmpty)
                            {
                                e.EventArguments[1].ArgumentName = "xoverlap";
                                e.EventArguments[1].ArgumentType = "int";
                                e.EventArguments[1].ArgumentValue = rIntersect.Width.ToString();

                                e.EventArguments[2].ArgumentName = "yoverlap";
                                e.EventArguments[2].ArgumentType = "int";
                                e.EventArguments[2].ArgumentValue = rIntersect.Height.ToString();
                            }

                            eventCollection.Add(e);

                        }
                    }
                }
            }
            // Empty the rectangles list
            rectangles.RemoveRange(0, rectangles.Count);
        
        }

    }
}
